package cn.silky.demo.security;

import cn.silky.demo.web.entity.SysAccount;
import cn.silky.demo.web.repository.SysAccountRepository;
import cn.silky.demo.web.service.ISysAccountService;
import cn.silky.demo.web.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

/**
 * @author ListJiang
 * @since 2021/11/9
 * description 自定义UserDetails服务
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class SecurityUserDetailsService implements ReactiveUserDetailsService,
        ReactiveUserDetailsPasswordService {
    private final ISysUserService iSysUserService;
    private final ISysAccountService iSysAccountService;
    private final SysAccountRepository sysAccountRepository;
    private final PasswordEncoder passwordEncoder;


    @Override
    public Mono<UserDetails> findByUsername(String username) {
        return iSysAccountService.findByAccount(username)
                .flatMap(sysAccount ->
                        iSysUserService.findSysUsersByAccountId(sysAccount::getId)
                                .flatMap(sysUser ->
                                        Mono.just(new SecurityUserDetails(sysAccount, sysUser))));
    }

    @Override
    public Mono<UserDetails> updatePassword(UserDetails user, String newPassword) {
        return Mono.just(user)
                .flatMap(userDetails -> {
                    if (userDetails instanceof SecurityUserDetails) {
                        SysAccount sysAccount = ((SecurityUserDetails) userDetails).getSysAccount();
                        sysAccount.setPassword(passwordEncoder.encode(newPassword));
                        return sysAccountRepository.save(sysAccount).map(sysAccount1 -> userDetails);
                    }
                    return Mono.just(userDetails);
                });
    }

}